phpseclib/Crypt/RSA.php
- 1
<?php
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77 if (!function_exists('crypt_random_string')) {
- 78 include_once 'Random.php';
- 79 }
- 80
- 81
- 82
- 83
- 84 if (!class_exists('Crypt_Hash')) {
- 85 include_once 'Hash.php';
- 86 }
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102 define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
- 103
- 104
- 105
- 106
- 107
- 108
- 109 define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
- 110
- 111
- 112
- 113
- 114
- 115
- 116 define('CRYPT_RSA_ENCRYPTION_NONE', 3);
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133 define('CRYPT_RSA_SIGNATURE_PSS', 1);
- 134
- 135
- 136
- 137
- 138
- 139
- 140 define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150 define('CRYPT_RSA_ASN1_INTEGER', 2);
- 151
- 152
- 153
- 154 define('CRYPT_RSA_ASN1_BITSTRING', 3);
- 155
- 156
- 157
- 158 define('CRYPT_RSA_ASN1_OCTETSTRING', 4);
- 159
- 160
- 161
- 162 define('CRYPT_RSA_ASN1_OBJECT', 6);
- 163
- 164
- 165
- 166 define('CRYPT_RSA_ASN1_SEQUENCE', 48);
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176 define('CRYPT_RSA_MODE_INTERNAL', 1);
- 177
- 178
- 179
- 180
- 181
- 182 define('CRYPT_RSA_MODE_OPENSSL', 2);
- 183
- 184
- 185
- 186
- 187
- 188 define('CRYPT_RSA_OPENSSL_CONFIG', dirname(__FILE__) . '/../openssl.cnf');
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200 define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
- 201
- 202
- 203
- 204 define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
- 205
- 206
- 207
- 208 define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
- 209
- 210
- 211
- 212 define('CRYPT_RSA_PRIVATE_FORMAT_PKCS8', 8);
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233 define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245 define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4);
- 246 define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW', 4);
- 247
- 248
- 249
- 250 define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
- 251
- 252
- 253
- 254
- 255
- 256 define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270 define('CRYPT_RSA_PUBLIC_FORMAT_PKCS8', 7);
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280 class Crypt_RSA
- 281 {
- 282
- 283
- 284
- 285
- 286
- 287
- 288 var $zero;
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296 var $one;
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304 var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312 var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS8;
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320 var $modulus;
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328 var $k;
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336 var $exponent;
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344 var $primes;
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352 var $exponents;
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360 var $coefficients;
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368 var $hashName;
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376 var $hash;
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384 var $hLen;
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392 var $sLen;
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400 var $mgfHash;
- 401
- 402
- 403
- 404
- 405
- 406
- 407
- 408 var $mgfHLen;
- 409
- 410
- 411
- 412
- 413
- 414
- 415
- 416 var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
- 417
- 418
- 419
- 420
- 421
- 422
- 423
- 424 var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
- 425
- 426
- 427
- 428
- 429
- 430
- 431
- 432 var $publicExponent = false;
- 433
- 434
- 435
- 436
- 437
- 438
- 439
- 440 var $password = false;
- 441
- 442
- 443
- 444
- 445
- 446
- 447
- 448
- 449
- 450
- 451
- 452 var $components = array();
- 453
- 454
- 455
- 456
- 457
- 458
- 459
- 460
- 461
- 462
- 463
- 464 var $current;
- 465
- 466
- 467
- 468
- 469
- 470
- 471
- 472
- 473
- 474 var $configFile;
- 475
- 476
- 477
- 478
- 479
- 480
- 481
- 482 var $comment = 'phpseclib-generated-key';
- 483
- 484
- 485
- 486
- 487
- 488
- 489
- 490
- 491
- 492
- 493
- 494 function __construct()
- 495 {
- 496 if (!class_exists('Math_BigInteger')) {
- 497 include_once 'Math/BigInteger.php';
- 498 }
- 499
- 500 $this->configFile = CRYPT_RSA_OPENSSL_CONFIG;
- 501
- 502 if (!defined('CRYPT_RSA_MODE')) {
- 503 switch (true) {
- 504
- 505
- 506
- 507 case defined('MATH_BIGINTEGER_OPENSSL_DISABLE'):
- 508 define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
- 509 break;
- 510
- 511 case !function_exists('openssl_pkey_get_details'):
- 512 define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
- 513 break;
- 514 case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>=') && file_exists($this->configFile):
- 515
- 516 ob_start();
- 517 @phpinfo();
- 518 $content = ob_get_contents();
- 519 ob_end_clean();
- 520
- 521 preg_match_all('#OpenSSL (Header|Library) Version(.*)#im', $content, $matches);
- 522
- 523 $versions = array();
- 524 if (!empty($matches[1])) {
- 525 for ($i = 0; $i < count($matches[1]); $i++) {
- 526 $fullVersion = trim(str_replace('=>', '', strip_tags($matches[2][$i])));
- 527
- 528
- 529 if (!preg_match('/(\d+\.\d+\.\d+)/i', $fullVersion, $m)) {
- 530 $versions[$matches[1][$i]] = $fullVersion;
- 531 } else {
- 532 $versions[$matches[1][$i]] = $m[0];
- 533 }
- 534 }
- 535 }
- 536
- 537
- 538 switch (true) {
- 539 case !isset($versions['Header']):
- 540 case !isset($versions['Library']):
- 541 case $versions['Header'] == $versions['Library']:
- 542 case version_compare($versions['Header'], '1.0.0') >= 0 && version_compare($versions['Library'], '1.0.0') >= 0:
- 543 define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
- 544 break;
- 545 default:
- 546 define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
- 547 define('MATH_BIGINTEGER_OPENSSL_DISABLE', true);
- 548 }
- 549 break;
- 550 default:
- 551 define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
- 552 }
- 553 }
- 554
- 555 $this->zero = new Math_BigInteger();
- 556 $this->one = new Math_BigInteger(1);
- 557
- 558 $this->hash = new Crypt_Hash('sha1');
- 559 $this->hLen = $this->hash->getLength();
- 560 $this->hashName = 'sha1';
- 561 $this->mgfHash = new Crypt_Hash('sha1');
- 562 $this->mgfHLen = $this->mgfHash->getLength();
- 563 }
- 564
- 565
- 566
- 567
- 568
- 569
- 570
- 571 function Crypt_RSA()
- 572 {
- 573 $this->__construct();
- 574 }
- 575
- 576
- 577
- 578
- 579
- 580
- 581
- 582
- 583
- 584
- 585
- 586
- 587
- 588
- 589
- 590 function createKey($bits = 1024, $timeout = false, $partial = array())
- 591 {
- 592 if (!defined('CRYPT_RSA_EXPONENT')) {
- 593
- 594 define('CRYPT_RSA_EXPONENT', '65537');
- 595 }
- 596
- 597
- 598
- 599
- 600
- 601
- 602 if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
- 603 define('CRYPT_RSA_SMALLEST_PRIME', 4096);
- 604 }
- 605
- 606
- 607 if (CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL && $bits >= 384 && CRYPT_RSA_EXPONENT == 65537) {
- 608 $config = array();
- 609 if (isset($this->configFile)) {
- 610 $config['config'] = $this->configFile;
- 611 }
- 612 $rsa = openssl_pkey_new(array('private_key_bits' => $bits) + $config);
- 613 openssl_pkey_export($rsa, $privatekey, null, $config);
- 614 $publickey = openssl_pkey_get_details($rsa);
- 615 $publickey = $publickey['key'];
- 616
- 617 $privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
- 618 $publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
- 619
- 620
- 621 while (openssl_error_string() !== false) {
- 622 }
- 623
- 624 return array(
- 625 'privatekey' => $privatekey,
- 626 'publickey' => $publickey,
- 627 'partialkey' => false
- 628 );
- 629 }
- 630
- 631 static $e;
- 632 if (!isset($e)) {
- 633 $e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
- 634 }
- 635
- 636 extract($this->_generateMinMax($bits));
- 637 $absoluteMin = $min;
- 638 $temp = $bits >> 1;
- 639 if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
- 640 $num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
- 641 $temp = CRYPT_RSA_SMALLEST_PRIME;
- 642 } else {
- 643 $num_primes = 2;
- 644 }
- 645 extract($this->_generateMinMax($temp + $bits % $temp));
- 646 $finalMax = $max;
- 647 extract($this->_generateMinMax($temp));
- 648
- 649 $generator = new Math_BigInteger();
- 650
- 651 $n = $this->one->copy();
- 652 if (!empty($partial)) {
- 653 extract(unserialize($partial));
- 654 } else {
- 655 $exponents = $coefficients = $primes = array();
- 656 $lcm = array(
- 657 'top' => $this->one->copy(),
- 658 'bottom' => false
- 659 );
- 660 }
- 661
- 662 $start = time();
- 663 $i0 = count($primes) + 1;
- 664
- 665 do {
- 666 for ($i = $i0; $i <= $num_primes; $i++) {
- 667 if ($timeout !== false) {
- 668 $timeout-= time() - $start;
- 669 $start = time();
- 670 if ($timeout <= 0) {
- 671 return array(
- 672 'privatekey' => '',
- 673 'publickey' => '',
- 674 'partialkey' => serialize(array(
- 675 'primes' => $primes,
- 676 'coefficients' => $coefficients,
- 677 'lcm' => $lcm,
- 678 'exponents' => $exponents
- 679 ))
- 680 );
- 681 }
- 682 }
- 683
- 684 if ($i == $num_primes) {
- 685 list($min, $temp) = $absoluteMin->divide($n);
- 686 if (!$temp->equals($this->zero)) {
- 687 $min = $min->add($this->one);
- 688 }
- 689 $primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
- 690 } else {
- 691 $primes[$i] = $generator->randomPrime($min, $max, $timeout);
- 692 }
- 693
- 694 if ($primes[$i] === false) {
- 695 if (count($primes) > 1) {
- 696 $partialkey = '';
- 697 } else {
- 698 array_pop($primes);
- 699 $partialkey = serialize(array(
- 700 'primes' => $primes,
- 701 'coefficients' => $coefficients,
- 702 'lcm' => $lcm,
- 703 'exponents' => $exponents
- 704 ));
- 705 }
- 706
- 707 return array(
- 708 'privatekey' => '',
- 709 'publickey' => '',
- 710 'partialkey' => $partialkey
- 711 );
- 712 }
- 713
- 714
- 715
- 716 if ($i > 2) {
- 717 $coefficients[$i] = $n->modInverse($primes[$i]);
- 718 }
- 719
- 720 $n = $n->multiply($primes[$i]);
- 721
- 722 $temp = $primes[$i]->subtract($this->one);
- 723
- 724
- 725
- 726 $lcm['top'] = $lcm['top']->multiply($temp);
- 727 $lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
- 728
- 729 $exponents[$i] = $e->modInverse($temp);
- 730 }
- 731
- 732 list($temp) = $lcm['top']->divide($lcm['bottom']);
- 733 $gcd = $temp->gcd($e);
- 734 $i0 = 1;
- 735 } while (!$gcd->equals($this->one));
- 736
- 737 $d = $e->modInverse($temp);
- 738
- 739 $coefficients[2] = $primes[2]->modInverse($primes[1]);
- 740
- 741
- 742
- 743
- 744
- 745
- 746
- 747
- 748
- 749
- 750
- 751
- 752
- 753
- 754
- 755 return array(
- 756 'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
- 757 'publickey' => $this->_convertPublicKey($n, $e),
- 758 'partialkey' => false
- 759 );
- 760 }
- 761
- 762
- 763
- 764
- 765
- 766
- 767
- 768
- 769
- 770 function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
- 771 {
- 772 $signed = $this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_XML;
- 773 $num_primes = count($primes);
- 774 $raw = array(
- 775 'version' => $num_primes == 2 ? chr(0) : chr(1),
- 776 'modulus' => $n->toBytes($signed),
- 777 'publicExponent' => $e->toBytes($signed),
- 778 'privateExponent' => $d->toBytes($signed),
- 779 'prime1' => $primes[1]->toBytes($signed),
- 780 'prime2' => $primes[2]->toBytes($signed),
- 781 'exponent1' => $exponents[1]->toBytes($signed),
- 782 'exponent2' => $exponents[2]->toBytes($signed),
- 783 'coefficient' => $coefficients[2]->toBytes($signed)
- 784 );
- 785
- 786
- 787
- 788 switch ($this->privateKeyFormat) {
- 789 case CRYPT_RSA_PRIVATE_FORMAT_XML:
- 790 if ($num_primes != 2) {
- 791 return false;
- 792 }
- 793 return "<RSAKeyValue>\r\n" .
- 794 ' <Modulus>' . base64_encode($raw['modulus']) . "</Modulus>\r\n" .
- 795 ' <Exponent>' . base64_encode($raw['publicExponent']) . "</Exponent>\r\n" .
- 796 ' <P>' . base64_encode($raw['prime1']) . "</P>\r\n" .
- 797 ' <Q>' . base64_encode($raw['prime2']) . "</Q>\r\n" .
- 798 ' <DP>' . base64_encode($raw['exponent1']) . "</DP>\r\n" .
- 799 ' <DQ>' . base64_encode($raw['exponent2']) . "</DQ>\r\n" .
- 800 ' <InverseQ>' . base64_encode($raw['coefficient']) . "</InverseQ>\r\n" .
- 801 ' <D>' . base64_encode($raw['privateExponent']) . "</D>\r\n" .
- 802 '</RSAKeyValue>';
- 803 break;
- 804 case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
- 805 if ($num_primes != 2) {
- 806 return false;
- 807 }
- 808 $key = "PuTTY-User-Key-File-2: ssh-rsa\r\nEncryption: ";
- 809 $encryption = (!empty($this->password) || is_string($this->password)) ? 'aes256-cbc' : 'none';
- 810 $key.= $encryption;
- 811 $key.= "\r\nComment: " . $this->comment . "\r\n";
- 812 $public = pack(
- 813 'Na*Na*Na*',
- 814 strlen('ssh-rsa'),
- 815 'ssh-rsa',
- 816 strlen($raw['publicExponent']),
- 817 $raw['publicExponent'],
- 818 strlen($raw['modulus']),
- 819 $raw['modulus']
- 820 );
- 821 $source = pack(
- 822 'Na*Na*Na*Na*',
- 823 strlen('ssh-rsa'),
- 824 'ssh-rsa',
- 825 strlen($encryption),
- 826 $encryption,
- 827 strlen($this->comment),
- 828 $this->comment,
- 829 strlen($public),
- 830 $public
- 831 );
- 832 $public = base64_encode($public);
- 833 $key.= "Public-Lines: " . ((strlen($public) + 63) >> 6) . "\r\n";
- 834 $key.= chunk_split($public, 64);
- 835 $private = pack(
- 836 'Na*Na*Na*Na*',
- 837 strlen($raw['privateExponent']),
- 838 $raw['privateExponent'],
- 839 strlen($raw['prime1']),
- 840 $raw['prime1'],
- 841 strlen($raw['prime2']),
- 842 $raw['prime2'],
- 843 strlen($raw['coefficient']),
- 844 $raw['coefficient']
- 845 );
- 846 if (empty($this->password) && !is_string($this->password)) {
- 847 $source.= pack('Na*', strlen($private), $private);
- 848 $hashkey = 'putty-private-key-file-mac-key';
- 849 } else {
- 850 $private.= crypt_random_string(16 - (strlen($private) & 15));
- 851 $source.= pack('Na*', strlen($private), $private);
- 852 if (!class_exists('Crypt_AES')) {
- 853 include_once 'Crypt/AES.php';
- 854 }
- 855 $sequence = 0;
- 856 $symkey = '';
- 857 while (strlen($symkey) < 32) {
- 858 $temp = pack('Na*', $sequence++, $this->password);
- 859 $symkey.= pack('H*', sha1($temp));
- 860 }
- 861 $symkey = substr($symkey, 0, 32);
- 862 $crypto = new Crypt_AES();
- 863
- 864 $crypto->setKey($symkey);
- 865 $crypto->disablePadding();
- 866 $private = $crypto->encrypt($private);
- 867 $hashkey = 'putty-private-key-file-mac-key' . $this->password;
- 868 }
- 869
- 870 $private = base64_encode($private);
- 871 $key.= 'Private-Lines: ' . ((strlen($private) + 63) >> 6) . "\r\n";
- 872 $key.= chunk_split($private, 64);
- 873 if (!class_exists('Crypt_Hash')) {
- 874 include_once 'Crypt/Hash.php';
- 875 }
- 876 $hash = new Crypt_Hash('sha1');
- 877 $hash->setKey(pack('H*', sha1($hashkey)));
- 878 $key.= 'Private-MAC: ' . bin2hex($hash->hash($source)) . "\r\n";
- 879
- 880 return $key;
- 881 default:
- 882 $components = array();
- 883 foreach ($raw as $name => $value) {
- 884 $components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
- 885 }
- 886
- 887 $RSAPrivateKey = implode('', $components);
- 888
- 889 if ($num_primes > 2) {
- 890 $OtherPrimeInfos = '';
- 891 for ($i = 3; $i <= $num_primes; $i++) {
- 892
- 893
- 894
- 895
- 896
- 897
- 898
- 899 $OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
- 900 $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
- 901 $OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
- 902 $OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
- 903 }
- 904 $RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
- 905 }
- 906
- 907 $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
- 908
- 909 if ($this->privateKeyFormat == CRYPT_RSA_PRIVATE_FORMAT_PKCS8) {
- 910 $rsaOID = pack('H*', '300d06092a864886f70d0101010500');
- 911 $RSAPrivateKey = pack(
- 912 'Ca*a*Ca*a*',
- 913 CRYPT_RSA_ASN1_INTEGER,
- 914 "\01\00",
- 915 $rsaOID,
- 916 4,
- 917 $this->_encodeLength(strlen($RSAPrivateKey)),
- 918 $RSAPrivateKey
- 919 );
- 920 $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
- 921 if (!empty($this->password) || is_string($this->password)) {
- 922 $salt = crypt_random_string(8);
- 923 $iterationCount = 2048;
- 924
- 925 if (!class_exists('Crypt_DES')) {
- 926 include_once 'Crypt/DES.php';
- 927 }
- 928 $crypto = new Crypt_DES();
- 929 $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
- 930 $RSAPrivateKey = $crypto->encrypt($RSAPrivateKey);
- 931
- 932 $parameters = pack(
- 933 'Ca*a*Ca*N',
- 934 CRYPT_RSA_ASN1_OCTETSTRING,
- 935 $this->_encodeLength(strlen($salt)),
- 936 $salt,
- 937 CRYPT_RSA_ASN1_INTEGER,
- 938 $this->_encodeLength(4),
- 939 $iterationCount
- 940 );
- 941 $pbeWithMD5AndDES_CBC = "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03";
- 942
- 943 $encryptionAlgorithm = pack(
- 944 'Ca*a*Ca*a*',
- 945 CRYPT_RSA_ASN1_OBJECT,
- 946 $this->_encodeLength(strlen($pbeWithMD5AndDES_CBC)),
- 947 $pbeWithMD5AndDES_CBC,
- 948 CRYPT_RSA_ASN1_SEQUENCE,
- 949 $this->_encodeLength(strlen($parameters)),
- 950 $parameters
- 951 );
- 952
- 953 $RSAPrivateKey = pack(
- 954 'Ca*a*Ca*a*',
- 955 CRYPT_RSA_ASN1_SEQUENCE,
- 956 $this->_encodeLength(strlen($encryptionAlgorithm)),
- 957 $encryptionAlgorithm,
- 958 CRYPT_RSA_ASN1_OCTETSTRING,
- 959 $this->_encodeLength(strlen($RSAPrivateKey)),
- 960 $RSAPrivateKey
- 961 );
- 962
- 963 $RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
- 964
- 965 $RSAPrivateKey = "-----BEGIN ENCRYPTED PRIVATE KEY-----\r\n" .
- 966 chunk_split(base64_encode($RSAPrivateKey), 64) .
- 967 '-----END ENCRYPTED PRIVATE KEY-----';
- 968 } else {
- 969 $RSAPrivateKey = "-----BEGIN PRIVATE KEY-----\r\n" .
- 970 chunk_split(base64_encode($RSAPrivateKey), 64) .
- 971 '-----END PRIVATE KEY-----';
- 972 }
- 973 return $RSAPrivateKey;
- 974 }
- 975
- 976 if (!empty($this->password) || is_string($this->password)) {
- 977 $iv = crypt_random_string(8);
- 978 $symkey = pack('H*', md5($this->password . $iv));
- 979 $symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
- 980 if (!class_exists('Crypt_TripleDES')) {
- 981 include_once 'Crypt/TripleDES.php';
- 982 }
- 983 $des = new Crypt_TripleDES();
- 984 $des->setKey($symkey);
- 985 $des->setIV($iv);
- 986 $iv = strtoupper(bin2hex($iv));
- 987 $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
- 988 "Proc-Type: 4,ENCRYPTED\r\n" .
- 989 "DEK-Info: DES-EDE3-CBC,$iv\r\n" .
- 990 "\r\n" .
- 991 chunk_split(base64_encode($des->encrypt($RSAPrivateKey)), 64) .
- 992 '-----END RSA PRIVATE KEY-----';
- 993 } else {
- 994 $RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
- 995 chunk_split(base64_encode($RSAPrivateKey), 64) .
- 996 '-----END RSA PRIVATE KEY-----';
- 997 }
- 998
- 999 return $RSAPrivateKey;
- 1000 }
- 1001 }
- 1002
- 1003
- 1004
- 1005
- 1006
- 1007
- 1008
- 1009
- 1010
- 1011 function _convertPublicKey($n, $e)
- 1012 {
- 1013 $signed = $this->publicKeyFormat != CRYPT_RSA_PUBLIC_FORMAT_XML;
- 1014
- 1015 $modulus = $n->toBytes($signed);
- 1016 $publicExponent = $e->toBytes($signed);
- 1017
- 1018 switch ($this->publicKeyFormat) {
- 1019 case CRYPT_RSA_PUBLIC_FORMAT_RAW:
- 1020 return array('e' => $e->copy(), 'n' => $n->copy());
- 1021 case CRYPT_RSA_PUBLIC_FORMAT_XML:
- 1022 return "<RSAKeyValue>\r\n" .
- 1023 ' <Modulus>' . base64_encode($modulus) . "</Modulus>\r\n" .
- 1024 ' <Exponent>' . base64_encode($publicExponent) . "</Exponent>\r\n" .
- 1025 '</RSAKeyValue>';
- 1026 break;
- 1027 case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
- 1028
- 1029
- 1030
- 1031
- 1032 $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
- 1033 $RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . $this->comment;
- 1034
- 1035 return $RSAPublicKey;
- 1036 default:
- 1037
- 1038
- 1039
- 1040
- 1041
- 1042 $components = array(
- 1043 'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
- 1044 'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
- 1045 );
- 1046
- 1047 $RSAPublicKey = pack(
- 1048 'Ca*a*a*',
- 1049 CRYPT_RSA_ASN1_SEQUENCE,
- 1050 $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
- 1051 $components['modulus'],
- 1052 $components['publicExponent']
- 1053 );
- 1054
- 1055 if ($this->publicKeyFormat == CRYPT_RSA_PUBLIC_FORMAT_PKCS1_RAW) {
- 1056 $RSAPublicKey = "-----BEGIN RSA PUBLIC KEY-----\r\n" .
- 1057 chunk_split(base64_encode($RSAPublicKey), 64) .
- 1058 '-----END RSA PUBLIC KEY-----';
- 1059 } else {
- 1060
- 1061 $rsaOID = pack('H*', '300d06092a864886f70d0101010500');
- 1062 $RSAPublicKey = chr(0) . $RSAPublicKey;
- 1063 $RSAPublicKey = chr(3) . $this->_encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
- 1064
- 1065 $RSAPublicKey = pack(
- 1066 'Ca*a*',
- 1067 CRYPT_RSA_ASN1_SEQUENCE,
- 1068 $this->_encodeLength(strlen($rsaOID . $RSAPublicKey)),
- 1069 $rsaOID . $RSAPublicKey
- 1070 );
- 1071
- 1072 $RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
- 1073 chunk_split(base64_encode($RSAPublicKey), 64) .
- 1074 '-----END PUBLIC KEY-----';
- 1075 }
- 1076
- 1077 return $RSAPublicKey;
- 1078 }
- 1079 }
- 1080
- 1081
- 1082
- 1083
- 1084
- 1085
- 1086
- 1087
- 1088
- 1089
- 1090
- 1091 function _parseKey($key, $type)
- 1092 {
- 1093 if ($type != CRYPT_RSA_PUBLIC_FORMAT_RAW && !is_string($key)) {
- 1094 return false;
- 1095 }
- 1096
- 1097 switch ($type) {
- 1098 case CRYPT_RSA_PUBLIC_FORMAT_RAW:
- 1099 if (!is_array($key)) {
- 1100 return false;
- 1101 }
- 1102 $components = array();
- 1103 switch (true) {
- 1104 case isset($key['e']):
- 1105 $components['publicExponent'] = $key['e']->copy();
- 1106 break;
- 1107 case isset($key['exponent']):
- 1108 $components['publicExponent'] = $key['exponent']->copy();
- 1109 break;
- 1110 case isset($key['publicExponent']):
- 1111 $components['publicExponent'] = $key['publicExponent']->copy();
- 1112 break;
- 1113 case isset($key[0]):
- 1114 $components['publicExponent'] = $key[0]->copy();
- 1115 }
- 1116 switch (true) {
- 1117 case isset($key['n']):
- 1118 $components['modulus'] = $key['n']->copy();
- 1119 break;
- 1120 case isset($key['modulo']):
- 1121 $components['modulus'] = $key['modulo']->copy();
- 1122 break;
- 1123 case isset($key['modulus']):
- 1124 $components['modulus'] = $key['modulus']->copy();
- 1125 break;
- 1126 case isset($key[1]):
- 1127 $components['modulus'] = $key[1]->copy();
- 1128 }
- 1129 return isset($components['modulus']) && isset($components['publicExponent']) ? $components : false;
- 1130 case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
- 1131 case CRYPT_RSA_PRIVATE_FORMAT_PKCS8:
- 1132 case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
- 1133
- 1134
- 1135
- 1136
- 1137
- 1138
- 1139
- 1140
- 1141
- 1142
- 1143
- 1144
- 1145
- 1146
- 1147
- 1148 if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
- 1149 $iv = pack('H*', trim($matches[2]));
- 1150 $symkey = pack('H*', md5($this->password . substr($iv, 0, 8)));
- 1151 $symkey.= pack('H*', md5($symkey . $this->password . substr($iv, 0, 8)));
- 1152
- 1153 $key = preg_replace('#^(?:Proc-Type|DEK-Info): .*#m', '', $key);
- 1154 $ciphertext = $this->_extractBER($key);
- 1155 if ($ciphertext === false) {
- 1156 $ciphertext = $key;
- 1157 }
- 1158 switch ($matches[1]) {
- 1159 case 'AES-256-CBC':
- 1160 if (!class_exists('Crypt_AES')) {
- 1161 include_once 'Crypt/AES.php';
- 1162 }
- 1163 $crypto = new Crypt_AES();
- 1164 break;
- 1165 case 'AES-128-CBC':
- 1166 if (!class_exists('Crypt_AES')) {
- 1167 include_once 'Crypt/AES.php';
- 1168 }
- 1169 $symkey = substr($symkey, 0, 16);
- 1170 $crypto = new Crypt_AES();
- 1171 break;
- 1172 case 'DES-EDE3-CFB':
- 1173 if (!class_exists('Crypt_TripleDES')) {
- 1174 include_once 'Crypt/TripleDES.php';
- 1175 }
- 1176 $crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
- 1177 break;
- 1178 case 'DES-EDE3-CBC':
- 1179 if (!class_exists('Crypt_TripleDES')) {
- 1180 include_once 'Crypt/TripleDES.php';
- 1181 }
- 1182 $symkey = substr($symkey, 0, 24);
- 1183 $crypto = new Crypt_TripleDES();
- 1184 break;
- 1185 case 'DES-CBC':
- 1186 if (!class_exists('Crypt_DES')) {
- 1187 include_once 'Crypt/DES.php';
- 1188 }
- 1189 $crypto = new Crypt_DES();
- 1190 break;
- 1191 default:
- 1192 return false;
- 1193 }
- 1194 $crypto->setKey($symkey);
- 1195 $crypto->setIV($iv);
- 1196 $decoded = $crypto->decrypt($ciphertext);
- 1197 } else {
- 1198 $decoded = $this->_extractBER($key);
- 1199 }
- 1200
- 1201 if ($decoded !== false) {
- 1202 $key = $decoded;
- 1203 }
- 1204
- 1205 $components = array();
- 1206
- 1207 if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
- 1208 return false;
- 1209 }
- 1210 if ($this->_decodeLength($key) != strlen($key)) {
- 1211 return false;
- 1212 }
- 1213
- 1214 $tag = ord($this->_string_shift($key));
- 1215
- 1216
- 1217
- 1218
- 1219
- 1220
- 1221
- 1222
- 1223
- 1224
- 1225
- 1226 if ($tag == CRYPT_RSA_ASN1_INTEGER && substr($key, 0, 3) == "\x01\x00\x30") {
- 1227 $this->_string_shift($key, 3);
- 1228 $tag = CRYPT_RSA_ASN1_SEQUENCE;
- 1229 }
- 1230
- 1231 if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
- 1232 $temp = $this->_string_shift($key, $this->_decodeLength($key));
- 1233 if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_OBJECT) {
- 1234 return false;
- 1235 }
- 1236 $length = $this->_decodeLength($temp);
- 1237 switch ($this->_string_shift($temp, $length)) {
- 1238 case "\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01":
- 1239 break;
- 1240 case "\x2a\x86\x48\x86\xf7\x0d\x01\x05\x03":
- 1241
- 1242
- 1243
- 1244
- 1245
- 1246 if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_SEQUENCE) {
- 1247 return false;
- 1248 }
- 1249 if ($this->_decodeLength($temp) != strlen($temp)) {
- 1250 return false;
- 1251 }
- 1252 $this->_string_shift($temp);
- 1253 $salt = $this->_string_shift($temp, $this->_decodeLength($temp));
- 1254 if (ord($this->_string_shift($temp)) != CRYPT_RSA_ASN1_INTEGER) {
- 1255 return false;
- 1256 }
- 1257 $this->_decodeLength($temp);
- 1258 list(, $iterationCount) = unpack('N', str_pad($temp, 4, chr(0), STR_PAD_LEFT));
- 1259 $this->_string_shift($key);
- 1260 $length = $this->_decodeLength($key);
- 1261 if (strlen($key) != $length) {
- 1262 return false;
- 1263 }
- 1264
- 1265 if (!class_exists('Crypt_DES')) {
- 1266 include_once 'Crypt/DES.php';
- 1267 }
- 1268 $crypto = new Crypt_DES();
- 1269 $crypto->setPassword($this->password, 'pbkdf1', 'md5', $salt, $iterationCount);
- 1270 $key = $crypto->decrypt($key);
- 1271 if ($key === false) {
- 1272 return false;
- 1273 }
- 1274 return $this->_parseKey($key, CRYPT_RSA_PRIVATE_FORMAT_PKCS1);
- 1275 default:
- 1276 return false;
- 1277 }
- 1278
- 1279
- 1280
- 1281
- 1282
- 1283
- 1284
- 1285 $tag = ord($this->_string_shift($key));
- 1286 $this->_decodeLength($key);
- 1287
- 1288
- 1289
- 1290 if ($tag == CRYPT_RSA_ASN1_BITSTRING) {
- 1291 $this->_string_shift($key);
- 1292 }
- 1293 if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
- 1294 return false;
- 1295 }
- 1296 if ($this->_decodeLength($key) != strlen($key)) {
- 1297 return false;
- 1298 }
- 1299 $tag = ord($this->_string_shift($key));
- 1300 }
- 1301 if ($tag != CRYPT_RSA_ASN1_INTEGER) {
- 1302 return false;
- 1303 }
- 1304
- 1305 $length = $this->_decodeLength($key);
- 1306 $temp = $this->_string_shift($key, $length);
- 1307 if (strlen($temp) != 1 || ord($temp) > 2) {
- 1308 $components['modulus'] = new Math_BigInteger($temp, 256);
- 1309 $this->_string_shift($key);
- 1310 $length = $this->_decodeLength($key);
- 1311 $components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
- 1312
- 1313 return $components;
- 1314 }
- 1315 if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
- 1316 return false;
- 1317 }
- 1318 $length = $this->_decodeLength($key);
- 1319 $components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
- 1320 $this->_string_shift($key);
- 1321 $length = $this->_decodeLength($key);
- 1322 $components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
- 1323 $this->_string_shift($key);
- 1324 $length = $this->_decodeLength($key);
- 1325 $components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), 256);
- 1326 $this->_string_shift($key);
- 1327 $length = $this->_decodeLength($key);
- 1328 $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
- 1329 $this->_string_shift($key);
- 1330 $length = $this->_decodeLength($key);
- 1331 $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
- 1332 $this->_string_shift($key);
- 1333 $length = $this->_decodeLength($key);
- 1334 $components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), 256));
- 1335 $this->_string_shift($key);
- 1336 $length = $this->_decodeLength($key);
- 1337 $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
- 1338 $this->_string_shift($key);
- 1339 $length = $this->_decodeLength($key);
- 1340 $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), 256));
- 1341
- 1342 if (!empty($key)) {
- 1343 if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
- 1344 return false;
- 1345 }
- 1346 $this->_decodeLength($key);
- 1347 while (!empty($key)) {
- 1348 if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
- 1349 return false;
- 1350 }
- 1351 $this->_decodeLength($key);
- 1352 $key = substr($key, 1);
- 1353 $length = $this->_decodeLength($key);
- 1354 $components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
- 1355 $this->_string_shift($key);
- 1356 $length = $this->_decodeLength($key);
- 1357 $components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
- 1358 $this->_string_shift($key);
- 1359 $length = $this->_decodeLength($key);
- 1360 $components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), 256);
- 1361 }
- 1362 }
- 1363
- 1364 return $components;
- 1365 case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
- 1366 $parts = explode(' ', $key, 3);
- 1367
- 1368 $key = isset($parts[1]) ? base64_decode($parts[1]) : false;
- 1369 if ($key === false) {
- 1370 return false;
- 1371 }
- 1372
- 1373 $comment = isset($parts[2]) ? $parts[2] : false;
- 1374
- 1375 $cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
- 1376
- 1377 if (strlen($key) <= 4) {
- 1378 return false;
- 1379 }
- 1380 extract(unpack('Nlength', $this->_string_shift($key, 4)));
- 1381 $publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
- 1382 if (strlen($key) <= 4) {
- 1383 return false;
- 1384 }
- 1385 extract(unpack('Nlength', $this->_string_shift($key, 4)));
- 1386 $modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
- 1387
- 1388 if ($cleanup && strlen($key)) {
- 1389 if (strlen($key) <= 4) {
- 1390 return false;
- 1391 }
- 1392 extract(unpack('Nlength', $this->_string_shift($key, 4)));
- 1393 $realModulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
- 1394 return strlen($key) ? false : array(
- 1395 'modulus' => $realModulus,
- 1396 'publicExponent' => $modulus,
- 1397 'comment' => $comment
- 1398 );
- 1399 } else {
- 1400 return strlen($key) ? false : array(
- 1401 'modulus' => $modulus,
- 1402 'publicExponent' => $publicExponent,
- 1403 'comment' => $comment
- 1404 );
- 1405 }
- 1406
- 1407
- 1408 case CRYPT_RSA_PRIVATE_FORMAT_XML:
- 1409 case CRYPT_RSA_PUBLIC_FORMAT_XML:
- 1410 $this->components = array();
- 1411
- 1412 $xml = xml_parser_create('UTF-8');
- 1413 xml_set_object($xml, $this);
- 1414 xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
- 1415 xml_set_character_data_handler($xml, '_data_handler');
- 1416
- 1417 if (!xml_parse($xml, '<xml>' . $key . '</xml>')) {
- 1418 return false;
- 1419 }
- 1420
- 1421 return isset($this->components['modulus']) && isset($this->components['publicExponent']) ? $this->components : false;
- 1422
- 1423 case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
- 1424 $components = array();
- 1425 $key = preg_split('#\r\n|\r|\n#', $key);
- 1426 $type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
- 1427 if ($type != 'ssh-rsa') {
- 1428 return false;
- 1429 }
- 1430 $encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
- 1431 $comment = trim(preg_replace('#Comment: (.+)#', '$1', $key[2]));
- 1432
- 1433 $publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
- 1434 $public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
- 1435 $public = substr($public, 11);
- 1436 extract(unpack('Nlength', $this->_string_shift($public, 4)));
- 1437 $components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
- 1438 extract(unpack('Nlength', $this->_string_shift($public, 4)));
- 1439 $components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
- 1440
- 1441 $privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
- 1442 $private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
- 1443
- 1444 switch ($encryption) {
- 1445 case 'aes256-cbc':
- 1446 if (!class_exists('Crypt_AES')) {
- 1447 include_once 'Crypt/AES.php';
- 1448 }
- 1449 $symkey = '';
- 1450 $sequence = 0;
- 1451 while (strlen($symkey) < 32) {
- 1452 $temp = pack('Na*', $sequence++, $this->password);
- 1453 $symkey.= pack('H*', sha1($temp));
- 1454 }
- 1455 $symkey = substr($symkey, 0, 32);
- 1456 $crypto = new Crypt_AES();
- 1457 }
- 1458
- 1459 if ($encryption != 'none') {
- 1460 $crypto->setKey($symkey);
- 1461 $crypto->disablePadding();
- 1462 $private = $crypto->decrypt($private);
- 1463 if ($private === false) {
- 1464 return false;
- 1465 }
- 1466 }
- 1467
- 1468 extract(unpack('Nlength', $this->_string_shift($private, 4)));
- 1469 if (strlen($private) < $length) {
- 1470 return false;
- 1471 }
- 1472 $components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256);
- 1473 extract(unpack('Nlength', $this->_string_shift($private, 4)));
- 1474 if (strlen($private) < $length) {
- 1475 return false;
- 1476 }
- 1477 $components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256));
- 1478 extract(unpack('Nlength', $this->_string_shift($private, 4)));
- 1479 if (strlen($private) < $length) {
- 1480 return false;
- 1481 }
- 1482 $components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256);
- 1483
- 1484 $temp = $components['primes'][1]->subtract($this->one);
- 1485 $components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
- 1486 $temp = $components['primes'][2]->subtract($this->one);
- 1487 $components['exponents'][] = $components['publicExponent']->modInverse($temp);
- 1488
- 1489 extract(unpack('Nlength', $this->_string_shift($private, 4)));
- 1490 if (strlen($private) < $length) {
- 1491 return false;
- 1492 }
- 1493 $components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256));
- 1494
- 1495 return $components;
- 1496 }
- 1497 }
- 1498
- 1499
- 1500
- 1501
- 1502
- 1503
- 1504
- 1505
- 1506
- 1507 function getSize()
- 1508 {
- 1509 return !isset($this->modulus) ? 0 : strlen($this->modulus->toBits());
- 1510 }
- 1511
- 1512
- 1513
- 1514
- 1515
- 1516
- 1517
- 1518
- 1519
- 1520
- 1521
- 1522 function _start_element_handler($parser, $name, $attribs)
- 1523 {
- 1524
- 1525 switch ($name) {
- 1526 case 'MODULUS':
- 1527 $this->current = &$this->components['modulus'];
- 1528 break;
- 1529 case 'EXPONENT':
- 1530 $this->current = &$this->components['publicExponent'];
- 1531 break;
- 1532 case 'P':
- 1533 $this->current = &$this->components['primes'][1];
- 1534 break;
- 1535 case 'Q':
- 1536 $this->current = &$this->components['primes'][2];
- 1537 break;
- 1538 case 'DP':
- 1539 $this->current = &$this->components['exponents'][1];
- 1540 break;
- 1541 case 'DQ':
- 1542 $this->current = &$this->components['exponents'][2];
- 1543 break;
- 1544 case 'INVERSEQ':
- 1545 $this->current = &$this->components['coefficients'][2];
- 1546 break;
- 1547 case 'D':
- 1548 $this->current = &$this->components['privateExponent'];
- 1549 }
- 1550 $this->current = '';
- 1551 }
- 1552
- 1553
- 1554
- 1555
- 1556
- 1557
- 1558
- 1559
- 1560
- 1561
- 1562 function _stop_element_handler($parser, $name)
- 1563 {
- 1564 if (isset($this->current)) {
- 1565 $this->current = new Math_BigInteger(base64_decode($this->current), 256);
- 1566 unset($this->current);
- 1567 }
- 1568 }
- 1569
- 1570
- 1571
- 1572
- 1573
- 1574
- 1575
- 1576
- 1577
- 1578
- 1579 function _data_handler($parser, $data)
- 1580 {
- 1581 if (!isset($this->current) || is_object($this->current)) {
- 1582 return;
- 1583 }
- 1584 $this->current.= trim($data);
- 1585 }
- 1586
- 1587
- 1588
- 1589
- 1590
- 1591
- 1592
- 1593
- 1594
- 1595
- 1596 function loadKey($key, $type = false)
- 1597 {
- 1598 if (is_object($key) && strtolower(get_class($key)) == 'crypt_rsa') {
- 1599 $this->privateKeyFormat = $key->privateKeyFormat;
- 1600 $this->publicKeyFormat = $key->publicKeyFormat;
- 1601 $this->k = $key->k;
- 1602 $this->hLen = $key->hLen;
- 1603 $this->sLen = $key->sLen;
- 1604 $this->mgfHLen = $key->mgfHLen;
- 1605 $this->encryptionMode = $key->encryptionMode;
- 1606 $this->signatureMode = $key->signatureMode;
- 1607 $this->password = $key->password;
- 1608 $this->configFile = $key->configFile;
- 1609 $this->comment = $key->comment;
- 1610
- 1611 if (is_object($key->hash)) {
- 1612 $this->hash = new Crypt_Hash($key->hash->getHash());
- 1613 }
- 1614 if (is_object($key->mgfHash)) {
- 1615 $this->mgfHash = new Crypt_Hash($key->mgfHash->getHash());
- 1616 }
- 1617
- 1618 if (is_object($key->modulus)) {
- 1619 $this->modulus = $key->modulus->copy();
- 1620 }
- 1621 if (is_object($key->exponent)) {
- 1622 $this->exponent = $key->exponent->copy();
- 1623 }
- 1624 if (is_object($key->publicExponent)) {
- 1625 $this->publicExponent = $key->publicExponent->copy();
- 1626 }
- 1627
- 1628 $this->primes = array();
- 1629 $this->exponents = array();
- 1630 $this->coefficients = array();
- 1631
- 1632 foreach ($this->primes as $prime) {
- 1633 $this->primes[] = $prime->copy();
- 1634 }
- 1635 foreach ($this->exponents as $exponent) {
- 1636 $this->exponents[] = $exponent->copy();
- 1637 }
- 1638 foreach ($this->coefficients as $coefficient) {
- 1639 $this->coefficients[] = $coefficient->copy();
- 1640 }
- 1641
- 1642 return true;
- 1643 }
- 1644
- 1645 if ($type === false) {
- 1646 $types = array(
- 1647 CRYPT_RSA_PUBLIC_FORMAT_RAW,
- 1648 CRYPT_RSA_PRIVATE_FORMAT_PKCS1,
- 1649 CRYPT_RSA_PRIVATE_FORMAT_XML,
- 1650 CRYPT_RSA_PRIVATE_FORMAT_PUTTY,
- 1651 CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
- 1652 );
- 1653 foreach ($types as $type) {
- 1654 $components = $this->_parseKey($key, $type);
- 1655 if ($components !== false) {
- 1656 break;
- 1657 }
- 1658 }
- 1659 } else {
- 1660 $components = $this->_parseKey($key, $type);
- 1661 }
- 1662
- 1663 if ($components === false) {
- 1664 $this->comment = null;
- 1665 $this->modulus = null;
- 1666 $this->k = null;
- 1667 $this->exponent = null;
- 1668 $this->primes = null;
- 1669 $this->exponents = null;
- 1670 $this->coefficients = null;
- 1671 $this->publicExponent = null;
- 1672
- 1673 return false;
- 1674 }
- 1675
- 1676 if (isset($components['comment']) && $components['comment'] !== false) {
- 1677 $this->comment = $components['comment'];
- 1678 }
- 1679 $this->modulus = $components['modulus'];
- 1680 $this->k = strlen($this->modulus->toBytes());
- 1681 $this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
- 1682 if (isset($components['primes'])) {
- 1683 $this->primes = $components['primes'];
- 1684 $this->exponents = $components['exponents'];
- 1685 $this->coefficients = $components['coefficients'];
- 1686 $this->publicExponent = $components['publicExponent'];
- 1687 } else {
- 1688 $this->primes = array();
- 1689 $this->exponents = array();
- 1690 $this->coefficients = array();
- 1691 $this->publicExponent = false;
- 1692 }
- 1693
- 1694 switch ($type) {
- 1695 case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
- 1696 case CRYPT_RSA_PUBLIC_FORMAT_RAW:
- 1697 $this->setPublicKey();
- 1698 break;
- 1699 case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
- 1700 switch (true) {
- 1701 case strpos($key, '-BEGIN PUBLIC KEY-') !== false:
- 1702 case strpos($key, '-BEGIN RSA PUBLIC KEY-') !== false:
- 1703 $this->setPublicKey();
- 1704 }
- 1705 }
- 1706
- 1707 return true;
- 1708 }
- 1709
- 1710
- 1711
- 1712
- 1713
- 1714
- 1715
- 1716
- 1717
- 1718
- 1719
- 1720
- 1721 function setPassword($password = false)
- 1722 {
- 1723 $this->password = $password;
- 1724 }
- 1725
- 1726
- 1727
- 1728
- 1729
- 1730
- 1731
- 1732
- 1733
- 1734
- 1735
- 1736
- 1737
- 1738
- 1739
- 1740
- 1741
- 1742
- 1743
- 1744
- 1745
- 1746
- 1747 function setPublicKey($key = false, $type = false)
- 1748 {
- 1749
- 1750 if (!empty($this->publicExponent)) {
- 1751 return false;
- 1752 }
- 1753
- 1754 if ($key === false && !empty($this->modulus)) {
- 1755 $this->publicExponent = $this->exponent;
- 1756 return true;
- 1757 }
- 1758
- 1759 if ($type === false) {
- 1760 $types = array(
- 1761 CRYPT_RSA_PUBLIC_FORMAT_RAW,
- 1762 CRYPT_RSA_PUBLIC_FORMAT_PKCS1,
- 1763 CRYPT_RSA_PUBLIC_FORMAT_XML,
- 1764 CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
- 1765 );
- 1766 foreach ($types as $type) {
- 1767 $components = $this->_parseKey($key, $type);
- 1768 if ($components !== false) {
- 1769 break;
- 1770 }
- 1771 }
- 1772 } else {
- 1773 $components = $this->_parseKey($key, $type);
- 1774 }
- 1775
- 1776 if ($components === false) {
- 1777 return false;
- 1778 }
- 1779
- 1780 if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
- 1781 $this->modulus = $components['modulus'];
- 1782 $this->exponent = $this->publicExponent = $components['publicExponent'];
- 1783 return true;
- 1784 }
- 1785
- 1786 $this->publicExponent = $components['publicExponent'];
- 1787
- 1788 return true;
- 1789 }
- 1790
- 1791
- 1792
- 1793
- 1794
- 1795
- 1796
- 1797
- 1798
- 1799
- 1800
- 1801
- 1802
- 1803
- 1804
- 1805
- 1806
- 1807 function setPrivateKey($key = false, $type = false)
- 1808 {
- 1809 if ($key === false && !empty($this->publicExponent)) {
- 1810 $this->publicExponent = false;
- 1811 return true;
- 1812 }
- 1813
- 1814 $rsa = new Crypt_RSA();
- 1815 if (!$rsa->loadKey($key, $type)) {
- 1816 return false;
- 1817 }
- 1818 $rsa->publicExponent = false;
- 1819
- 1820
- 1821 $this->loadKey($rsa);
- 1822 return true;
- 1823 }
- 1824
- 1825
- 1826
- 1827
- 1828
- 1829
- 1830
- 1831
- 1832
- 1833
- 1834
- 1835
- 1836
- 1837 function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS8)
- 1838 {
- 1839 if (empty($this->modulus) || empty($this->publicExponent)) {
- 1840 return false;
- 1841 }
- 1842
- 1843 $oldFormat = $this->publicKeyFormat;
- 1844 $this->publicKeyFormat = $type;
- 1845 $temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
- 1846 $this->publicKeyFormat = $oldFormat;
- 1847 return $temp;
- 1848 }
- 1849
- 1850
- 1851
- 1852
- 1853
- 1854
- 1855
- 1856
- 1857
- 1858
- 1859
- 1860
- 1861
- 1862 function getPublicKeyFingerprint($algorithm = 'md5')
- 1863 {
- 1864 if (empty($this->modulus) || empty($this->publicExponent)) {
- 1865 return false;
- 1866 }
- 1867
- 1868 $modulus = $this->modulus->toBytes(true);
- 1869 $publicExponent = $this->publicExponent->toBytes(true);
- 1870
- 1871 $RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
- 1872
- 1873 switch ($algorithm) {
- 1874 case 'sha256':
- 1875 $hash = new Crypt_Hash('sha256');
- 1876 $base = base64_encode($hash->hash($RSAPublicKey));
- 1877 return substr($base, 0, strlen($base) - 1);
- 1878 case 'md5':
- 1879 return substr(chunk_split(md5($RSAPublicKey), 2, ':'), 0, -1);
- 1880 default:
- 1881 return false;
- 1882 }
- 1883 }
- 1884
- 1885
- 1886
- 1887
- 1888
- 1889
- 1890
- 1891
- 1892
- 1893
- 1894
- 1895
- 1896 function getPrivateKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
- 1897 {
- 1898 if (empty($this->primes)) {
- 1899 return false;
- 1900 }
- 1901
- 1902 $oldFormat = $this->privateKeyFormat;
- 1903 $this->privateKeyFormat = $type;
- 1904 $temp = $this->_convertPrivateKey($this->modulus, $this->publicExponent, $this->exponent, $this->primes, $this->exponents, $this->coefficients);
- 1905 $this->privateKeyFormat = $oldFormat;
- 1906 return $temp;
- 1907 }
- 1908
- 1909
- 1910
- 1911
- 1912
- 1913
- 1914
- 1915
- 1916
- 1917
- 1918
- 1919
- 1920 function _getPrivatePublicKey($mode = CRYPT_RSA_PUBLIC_FORMAT_PKCS8)
- 1921 {
- 1922 if (empty($this->modulus) || empty($this->exponent)) {
- 1923 return false;
- 1924 }
- 1925
- 1926 $oldFormat = $this->publicKeyFormat;
- 1927 $this->publicKeyFormat = $mode;
- 1928 $temp = $this->_convertPublicKey($this->modulus, $this->exponent);
- 1929 $this->publicKeyFormat = $oldFormat;
- 1930 return $temp;
- 1931 }
- 1932
- 1933
- 1934
- 1935
- 1936
- 1937
- 1938
- 1939 function __toString()
- 1940 {
- 1941 $key = $this->getPrivateKey($this->privateKeyFormat);
- 1942 if ($key !== false) {
- 1943 return $key;
- 1944 }
- 1945 $key = $this->_getPrivatePublicKey($this->publicKeyFormat);
- 1946 return $key !== false ? $key : '';
- 1947 }
- 1948
- 1949
- 1950
- 1951
- 1952
- 1953
- 1954
- 1955 function __clone()
- 1956 {
- 1957 $key = new Crypt_RSA();
- 1958 $key->loadKey($this);
- 1959 return $key;
- 1960 }
- 1961
- 1962
- 1963
- 1964
- 1965
- 1966
- 1967
- 1968
- 1969 function _generateMinMax($bits)
- 1970 {
- 1971 $bytes = $bits >> 3;
- 1972 $min = str_repeat(chr(0), $bytes);
- 1973 $max = str_repeat(chr(0xFF), $bytes);
- 1974 $msb = $bits & 7;
- 1975 if ($msb) {
- 1976 $min = chr(1 << ($msb - 1)) . $min;
- 1977 $max = chr((1 << $msb) - 1) . $max;
- 1978 } else {
- 1979 $min[0] = chr(0x80);
- 1980 }
- 1981
- 1982 return array(
- 1983 'min' => new Math_BigInteger($min, 256),
- 1984 'max' => new Math_BigInteger($max, 256)
- 1985 );
- 1986 }
- 1987
- 1988
- 1989
- 1990
- 1991
- 1992
- 1993
- 1994
- 1995
- 1996
- 1997
- 1998 function _decodeLength(&$string)
- 1999 {
- 2000 $length = ord($this->_string_shift($string));
- 2001 if ($length & 0x80) {
- 2002 $length&= 0x7F;
- 2003 $temp = $this->_string_shift($string, $length);
- 2004 list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
- 2005 }
- 2006 return $length;
- 2007 }
- 2008
- 2009
- 2010
- 2011
- 2012
- 2013
- 2014
- 2015
- 2016
- 2017
- 2018
- 2019 function _encodeLength($length)
- 2020 {
- 2021 if ($length <= 0x7F) {
- 2022 return chr($length);
- 2023 }
- 2024
- 2025 $temp = ltrim(pack('N', $length), chr(0));
- 2026 return pack('Ca*', 0x80 | strlen($temp), $temp);
- 2027 }
- 2028
- 2029
- 2030
- 2031
- 2032
- 2033
- 2034
- 2035
- 2036
- 2037
- 2038
- 2039 function _string_shift(&$string, $index = 1)
- 2040 {
- 2041 $substr = substr($string, 0, $index);
- 2042 $string = substr($string, $index);
- 2043 return $substr;
- 2044 }
- 2045
- 2046
- 2047
- 2048
- 2049
- 2050
- 2051
- 2052
- 2053 function setPrivateKeyFormat($format)
- 2054 {
- 2055 $this->privateKeyFormat = $format;
- 2056 }
- 2057
- 2058
- 2059
- 2060
- 2061
- 2062
- 2063
- 2064
- 2065 function setPublicKeyFormat($format)
- 2066 {
- 2067 $this->publicKeyFormat = $format;
- 2068 }
- 2069
- 2070
- 2071
- 2072
- 2073
- 2074
- 2075
- 2076
- 2077
- 2078
- 2079 function setHash($hash)
- 2080 {
- 2081
- 2082 switch ($hash) {
- 2083 case 'md2':
- 2084 case 'md5':
- 2085 case 'sha1':
- 2086 case 'sha256':
- 2087 case 'sha384':
- 2088 case 'sha512':
- 2089 $this->hash = new Crypt_Hash($hash);
- 2090 $this->hashName = $hash;
- 2091 break;
- 2092 default:
- 2093 $this->hash = new Crypt_Hash('sha1');
- 2094 $this->hashName = 'sha1';
- 2095 }
- 2096 $this->hLen = $this->hash->getLength();
- 2097 }
- 2098
- 2099
- 2100
- 2101
- 2102
- 2103
- 2104
- 2105
- 2106
- 2107
- 2108 function setMGFHash($hash)
- 2109 {
- 2110
- 2111 switch ($hash) {
- 2112 case 'md2':
- 2113 case 'md5':
- 2114 case 'sha1':
- 2115 case 'sha256':
- 2116 case 'sha384':
- 2117 case 'sha512':
- 2118 $this->mgfHash = new Crypt_Hash($hash);
- 2119 break;
- 2120 default:
- 2121 $this->mgfHash = new Crypt_Hash('sha1');
- 2122 }
- 2123 $this->mgfHLen = $this->mgfHash->getLength();
- 2124 }
- 2125
- 2126
- 2127
- 2128
- 2129
- 2130
- 2131
- 2132
- 2133
- 2134
- 2135
- 2136
- 2137 function setSaltLength($sLen)
- 2138 {
- 2139 $this->sLen = $sLen;
- 2140 }
- 2141
- 2142
- 2143
- 2144
- 2145
- 2146
- 2147
- 2148
- 2149
- 2150
- 2151
- 2152 function _i2osp($x, $xLen)
- 2153 {
- 2154 $x = $x->toBytes();
- 2155 if (strlen($x) > $xLen) {
- 2156 user_error('Integer too large');
- 2157 return false;
- 2158 }
- 2159 return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
- 2160 }
- 2161
- 2162
- 2163
- 2164
- 2165
- 2166
- 2167
- 2168
- 2169
- 2170
- 2171 function _os2ip($x)
- 2172 {
- 2173 return new Math_BigInteger($x, 256);
- 2174 }
- 2175
- 2176
- 2177
- 2178
- 2179
- 2180
- 2181
- 2182
- 2183
- 2184
- 2185 function _exponentiate($x)
- 2186 {
- 2187 switch (true) {
- 2188 case empty($this->primes):
- 2189 case $this->primes[1]->equals($this->zero):
- 2190 case empty($this->coefficients):
- 2191 case $this->coefficients[2]->equals($this->zero):
- 2192 case empty($this->exponents):
- 2193 case $this->exponents[1]->equals($this->zero):
- 2194 return $x->modPow($this->exponent, $this->modulus);
- 2195 }
- 2196
- 2197 $num_primes = count($this->primes);
- 2198
- 2199 if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
- 2200 $m_i = array(
- 2201 1 => $x->modPow($this->exponents[1], $this->primes[1]),
- 2202 2 => $x->modPow($this->exponents[2], $this->primes[2])
- 2203 );
- 2204 $h = $m_i[1]->subtract($m_i[2]);
- 2205 $h = $h->multiply($this->coefficients[2]);
- 2206 list(, $h) = $h->divide($this->primes[1]);
- 2207 $m = $m_i[2]->add($h->multiply($this->primes[2]));
- 2208
- 2209 $r = $this->primes[1];
- 2210 for ($i = 3; $i <= $num_primes; $i++) {
- 2211 $m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
- 2212
- 2213 $r = $r->multiply($this->primes[$i - 1]);
- 2214
- 2215 $h = $m_i->subtract($m);
- 2216 $h = $h->multiply($this->coefficients[$i]);
- 2217 list(, $h) = $h->divide($this->primes[$i]);
- 2218
- 2219 $m = $m->add($r->multiply($h));
- 2220 }
- 2221 } else {
- 2222 $smallest = $this->primes[1];
- 2223 for ($i = 2; $i <= $num_primes; $i++) {
- 2224 if ($smallest->compare($this->primes[$i]) > 0) {
- 2225 $smallest = $this->primes[$i];
- 2226 }
- 2227 }
- 2228
- 2229 $one = new Math_BigInteger(1);
- 2230
- 2231 $r = $one->random($one, $smallest->subtract($one));
- 2232
- 2233 $m_i = array(
- 2234 1 => $this->_blind($x, $r, 1),
- 2235 2 => $this->_blind($x, $r, 2)
- 2236 );
- 2237 $h = $m_i[1]->subtract($m_i[2]);
- 2238 $h = $h->multiply($this->coefficients[2]);
- 2239 list(, $h) = $h->divide($this->primes[1]);
- 2240 $m = $m_i[2]->add($h->multiply($this->primes[2]));
- 2241
- 2242 $r = $this->primes[1];
- 2243 for ($i = 3; $i <= $num_primes; $i++) {
- 2244 $m_i = $this->_blind($x, $r, $i);
- 2245
- 2246 $r = $r->multiply($this->primes[$i - 1]);
- 2247
- 2248 $h = $m_i->subtract($m);
- 2249 $h = $h->multiply($this->coefficients[$i]);
- 2250 list(, $h) = $h->divide($this->primes[$i]);
- 2251
- 2252 $m = $m->add($r->multiply($h));
- 2253 }
- 2254 }
- 2255
- 2256 return $m;
- 2257 }
- 2258
- 2259
- 2260
- 2261
- 2262
- 2263
- 2264
- 2265
- 2266
- 2267
- 2268
- 2269
- 2270
- 2271 function _blind($x, $r, $i)
- 2272 {
- 2273 $x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
- 2274 $x = $x->modPow($this->exponents[$i], $this->primes[$i]);
- 2275
- 2276 $r = $r->modInverse($this->primes[$i]);
- 2277 $x = $x->multiply($r);
- 2278 list(, $x) = $x->divide($this->primes[$i]);
- 2279
- 2280 return $x;
- 2281 }
- 2282
- 2283
- 2284
- 2285
- 2286
- 2287
- 2288
- 2289
- 2290
- 2291
- 2292
- 2293
- 2294
- 2295
- 2296
- 2297 function _equals($x, $y)
- 2298 {
- 2299 if (strlen($x) != strlen($y)) {
- 2300 return false;
- 2301 }
- 2302
- 2303 $result = 0;
- 2304 for ($i = 0; $i < strlen($x); $i++) {
- 2305 $result |= ord($x[$i]) ^ ord($y[$i]);
- 2306 }
- 2307
- 2308 return $result == 0;
- 2309 }
- 2310
- 2311
- 2312
- 2313
- 2314
- 2315
- 2316
- 2317
- 2318
- 2319
- 2320 function _rsaep($m)
- 2321 {
- 2322 if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
- 2323 user_error('Message representative out of range');
- 2324 return false;
- 2325 }
- 2326 return $this->_exponentiate($m);
- 2327 }
- 2328
- 2329
- 2330
- 2331
- 2332
- 2333
- 2334
- 2335
- 2336
- 2337
- 2338 function _rsadp($c)
- 2339 {
- 2340 if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
- 2341 user_error('Ciphertext representative out of range');
- 2342 return false;
- 2343 }
- 2344 return $this->_exponentiate($c);
- 2345 }
- 2346
- 2347
- 2348
- 2349
- 2350
- 2351
- 2352
- 2353
- 2354
- 2355
- 2356 function _rsasp1($m)
- 2357 {
- 2358 if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
- 2359 user_error('Message representative out of range');
- 2360 return false;
- 2361 }
- 2362 return $this->_exponentiate($m);
- 2363 }
- 2364
- 2365
- 2366
- 2367
- 2368
- 2369
- 2370
- 2371
- 2372
- 2373
- 2374 function _rsavp1($s)
- 2375 {
- 2376 if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
- 2377 user_error('Signature representative out of range');
- 2378 return false;
- 2379 }
- 2380 return $this->_exponentiate($s);
- 2381 }
- 2382
- 2383
- 2384
- 2385
- 2386
- 2387
- 2388
- 2389
- 2390
- 2391
- 2392
- 2393 function _mgf1($mgfSeed, $maskLen)
- 2394 {
- 2395
- 2396
- 2397 $t = '';
- 2398 $count = ceil($maskLen / $this->mgfHLen);
- 2399 for ($i = 0; $i < $count; $i++) {
- 2400 $c = pack('N', $i);
- 2401 $t.= $this->mgfHash->hash($mgfSeed . $c);
- 2402 }
- 2403
- 2404 return substr($t, 0, $maskLen);
- 2405 }
- 2406
- 2407
- 2408
- 2409
- 2410
- 2411
- 2412
- 2413
- 2414
- 2415
- 2416
- 2417
- 2418 function _rsaes_oaep_encrypt($m, $l = '')
- 2419 {
- 2420 $mLen = strlen($m);
- 2421
- 2422
- 2423
- 2424
- 2425
- 2426
- 2427 if ($mLen > $this->k - 2 * $this->hLen - 2) {
- 2428 user_error('Message too long');
- 2429 return false;
- 2430 }
- 2431
- 2432
- 2433
- 2434 $lHash = $this->hash->hash($l);
- 2435 $ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
- 2436 $db = $lHash . $ps . chr(1) . $m;
- 2437 $seed = crypt_random_string($this->hLen);
- 2438 $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
- 2439 $maskedDB = $db ^ $dbMask;
- 2440 $seedMask = $this->_mgf1($maskedDB, $this->hLen);
- 2441 $maskedSeed = $seed ^ $seedMask;
- 2442 $em = chr(0) . $maskedSeed . $maskedDB;
- 2443
- 2444
- 2445
- 2446 $m = $this->_os2ip($em);
- 2447 $c = $this->_rsaep($m);
- 2448 $c = $this->_i2osp($c, $this->k);
- 2449
- 2450
- 2451
- 2452 return $c;
- 2453 }
- 2454
- 2455
- 2456
- 2457
- 2458
- 2459
- 2460
- 2461
- 2462
- 2463
- 2464
- 2465
- 2466
- 2467
- 2468
- 2469
- 2470
- 2471
- 2472
- 2473
- 2474
- 2475
- 2476
- 2477
- 2478
- 2479
- 2480
- 2481 function _rsaes_oaep_decrypt($c, $l = '')
- 2482 {
- 2483
- 2484
- 2485
- 2486
- 2487
- 2488 if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
- 2489 user_error('Decryption error');
- 2490 return false;
- 2491 }
- 2492
- 2493
- 2494
- 2495 $c = $this->_os2ip($c);
- 2496 $m = $this->_rsadp($c);
- 2497 if ($m === false) {
- 2498 user_error('Decryption error');
- 2499 return false;
- 2500 }
- 2501 $em = $this->_i2osp($m, $this->k);
- 2502
- 2503
- 2504
- 2505 $lHash = $this->hash->hash($l);
- 2506 $y = ord($em[0]);
- 2507 $maskedSeed = substr($em, 1, $this->hLen);
- 2508 $maskedDB = substr($em, $this->hLen + 1);
- 2509 $seedMask = $this->_mgf1($maskedDB, $this->hLen);
- 2510 $seed = $maskedSeed ^ $seedMask;
- 2511 $dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
- 2512 $db = $maskedDB ^ $dbMask;
- 2513 $lHash2 = substr($db, 0, $this->hLen);
- 2514 $m = substr($db, $this->hLen);
- 2515 if (!$this->_equals($lHash, $lHash2)) {
- 2516 user_error('Decryption error');
- 2517 return false;
- 2518 }
- 2519 $m = ltrim($m, chr(0));
- 2520 if (ord($m[0]) != 1) {
- 2521 user_error('Decryption error');
- 2522 return false;
- 2523 }
- 2524
- 2525
- 2526
- 2527 return substr($m, 1);
- 2528 }
- 2529
- 2530
- 2531
- 2532
- 2533
- 2534
- 2535
- 2536
- 2537
- 2538
- 2539 function _raw_encrypt($m)
- 2540 {
- 2541 $temp = $this->_os2ip($m);
- 2542 $temp = $this->_rsaep($temp);
- 2543 return $this->_i2osp($temp, $this->k);
- 2544 }
- 2545
- 2546
- 2547
- 2548
- 2549
- 2550
- 2551
- 2552
- 2553
- 2554
- 2555 function _rsaes_pkcs1_v1_5_encrypt($m)
- 2556 {
- 2557 $mLen = strlen($m);
- 2558
- 2559
- 2560
- 2561 if ($mLen > $this->k - 11) {
- 2562 user_error('Message too long');
- 2563 return false;
- 2564 }
- 2565
- 2566
- 2567
- 2568 $psLen = $this->k - $mLen - 3;
- 2569 $ps = '';
- 2570 while (strlen($ps) != $psLen) {
- 2571 $temp = crypt_random_string($psLen - strlen($ps));
- 2572 $temp = str_replace("\x00", '', $temp);
- 2573 $ps.= $temp;
- 2574 }
- 2575 $type = 2;
- 2576
- 2577 if (defined('CRYPT_RSA_PKCS15_COMPAT') && (!isset($this->publicExponent) || $this->exponent !== $this->publicExponent)) {
- 2578 $type = 1;
- 2579
- 2580 $ps = str_repeat("\xFF", $psLen);
- 2581 }
- 2582 $em = chr(0) . chr($type) . $ps . chr(0) . $m;
- 2583
- 2584
- 2585 $m = $this->_os2ip($em);
- 2586 $c = $this->_rsaep($m);
- 2587 $c = $this->_i2osp($c, $this->k);
- 2588
- 2589
- 2590
- 2591 return $c;
- 2592 }
- 2593
- 2594
- 2595
- 2596
- 2597
- 2598
- 2599
- 2600
- 2601
- 2602
- 2603
- 2604
- 2605
- 2606
- 2607
- 2608
- 2609
- 2610
- 2611
- 2612
- 2613
- 2614 function _rsaes_pkcs1_v1_5_decrypt($c)
- 2615 {
- 2616
- 2617
- 2618 if (strlen($c) != $this->k) {
- 2619 user_error('Decryption error');
- 2620 return false;
- 2621 }
- 2622
- 2623
- 2624
- 2625 $c = $this->_os2ip($c);
- 2626 $m = $this->_rsadp($c);
- 2627
- 2628 if ($m === false) {
- 2629 user_error('Decryption error');
- 2630 return false;
- 2631 }
- 2632 $em = $this->_i2osp($m, $this->k);
- 2633
- 2634
- 2635
- 2636 if (ord($em[0]) != 0 || ord($em[1]) > 2) {
- 2637 user_error('Decryption error');
- 2638 return false;
- 2639 }
- 2640
- 2641 $ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
- 2642 $m = substr($em, strlen($ps) + 3);
- 2643
- 2644 if (strlen($ps) < 8) {
- 2645 user_error('Decryption error');
- 2646 return false;
- 2647 }
- 2648
- 2649
- 2650
- 2651 return $m;
- 2652 }
- 2653
- 2654
- 2655
- 2656
- 2657
- 2658
- 2659
- 2660
- 2661
- 2662
- 2663 function _emsa_pss_encode($m, $emBits)
- 2664 {
- 2665
- 2666
- 2667
- 2668 $emLen = ($emBits + 1) >> 3;
- 2669 $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
- 2670
- 2671 $mHash = $this->hash->hash($m);
- 2672 if ($emLen < $this->hLen + $sLen + 2) {
- 2673 user_error('Encoding error');
- 2674 return false;
- 2675 }
- 2676
- 2677 $salt = crypt_random_string($sLen);
- 2678 $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
- 2679 $h = $this->hash->hash($m2);
- 2680 $ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
- 2681 $db = $ps . chr(1) . $salt;
- 2682 $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
- 2683 $maskedDB = $db ^ $dbMask;
- 2684 $maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
- 2685 $em = $maskedDB . $h . chr(0xBC);
- 2686
- 2687 return $em;
- 2688 }
- 2689
- 2690
- 2691
- 2692
- 2693
- 2694
- 2695
- 2696
- 2697
- 2698
- 2699
- 2700
- 2701 function _emsa_pss_verify($m, $em, $emBits)
- 2702 {
- 2703
- 2704
- 2705
- 2706 $emLen = ($emBits + 1) >> 3;
- 2707 $sLen = $this->sLen !== null ? $this->sLen : $this->hLen;
- 2708
- 2709 $mHash = $this->hash->hash($m);
- 2710 if ($emLen < $this->hLen + $sLen + 2) {
- 2711 return false;
- 2712 }
- 2713
- 2714 if ($em[strlen($em) - 1] != chr(0xBC)) {
- 2715 return false;
- 2716 }
- 2717
- 2718 $maskedDB = substr($em, 0, -$this->hLen - 1);
- 2719 $h = substr($em, -$this->hLen - 1, $this->hLen);
- 2720 $temp = chr(0xFF << ($emBits & 7));
- 2721 if ((~$maskedDB[0] & $temp) != $temp) {
- 2722 return false;
- 2723 }
- 2724 $dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
- 2725 $db = $maskedDB ^ $dbMask;
- 2726 $db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
- 2727 $temp = $emLen - $this->hLen - $sLen - 2;
- 2728 if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
- 2729 return false;
- 2730 }
- 2731 $salt = substr($db, $temp + 1);
- 2732 $m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
- 2733 $h2 = $this->hash->hash($m2);
- 2734 return $this->_equals($h, $h2);
- 2735 }
- 2736
- 2737
- 2738
- 2739
- 2740
- 2741
- 2742
- 2743
- 2744
- 2745
- 2746 function _rsassa_pss_sign($m)
- 2747 {
- 2748
- 2749
- 2750 $em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
- 2751
- 2752
- 2753
- 2754 $m = $this->_os2ip($em);
- 2755 $s = $this->_rsasp1($m);
- 2756 $s = $this->_i2osp($s, $this->k);
- 2757
- 2758
- 2759
- 2760 return $s;
- 2761 }
- 2762
- 2763
- 2764
- 2765
- 2766
- 2767
- 2768
- 2769
- 2770
- 2771
- 2772
- 2773 function _rsassa_pss_verify($m, $s)
- 2774 {
- 2775
- 2776
- 2777 if (strlen($s) != $this->k) {
- 2778 user_error('Invalid signature');
- 2779 return false;
- 2780 }
- 2781
- 2782
- 2783
- 2784 $modBits = 8 * $this->k;
- 2785
- 2786 $s2 = $this->_os2ip($s);
- 2787 $m2 = $this->_rsavp1($s2);
- 2788 if ($m2 === false) {
- 2789 user_error('Invalid signature');
- 2790 return false;
- 2791 }
- 2792 $em = $this->_i2osp($m2, $modBits >> 3);
- 2793 if ($em === false) {
- 2794 user_error('Invalid signature');
- 2795 return false;
- 2796 }
- 2797
- 2798
- 2799
- 2800 return $this->_emsa_pss_verify($m, $em, $modBits - 1);
- 2801 }
- 2802
- 2803
- 2804
- 2805
- 2806
- 2807
- 2808
- 2809
- 2810
- 2811
- 2812
- 2813 function _emsa_pkcs1_v1_5_encode($m, $emLen)
- 2814 {
- 2815 $h = $this->hash->hash($m);
- 2816 if ($h === false) {
- 2817 return false;
- 2818 }
- 2819
- 2820
- 2821 switch ($this->hashName) {
- 2822 case 'md2':
- 2823 $t = pack('H*', '3020300c06082a864886f70d020205000410');
- 2824 break;
- 2825 case 'md5':
- 2826 $t = pack('H*', '3020300c06082a864886f70d020505000410');
- 2827 break;
- 2828 case 'sha1':
- 2829 $t = pack('H*', '3021300906052b0e03021a05000414');
- 2830 break;
- 2831 case 'sha256':
- 2832 $t = pack('H*', '3031300d060960864801650304020105000420');
- 2833 break;
- 2834 case 'sha384':
- 2835 $t = pack('H*', '3041300d060960864801650304020205000430');
- 2836 break;
- 2837 case 'sha512':
- 2838 $t = pack('H*', '3051300d060960864801650304020305000440');
- 2839 }
- 2840 $t.= $h;
- 2841 $tLen = strlen($t);
- 2842
- 2843 if ($emLen < $tLen + 11) {
- 2844 user_error('Intended encoded message length too short');
- 2845 return false;
- 2846 }
- 2847
- 2848 $ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
- 2849
- 2850 $em = "\0\1$ps\0$t";
- 2851
- 2852 return $em;
- 2853 }
- 2854
- 2855
- 2856
- 2857
- 2858
- 2859
- 2860
- 2861
- 2862
- 2863
- 2864 function _rsassa_pkcs1_v1_5_sign($m)
- 2865 {
- 2866
- 2867
- 2868 $em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
- 2869 if ($em === false) {
- 2870 user_error('RSA modulus too short');
- 2871 return false;
- 2872 }
- 2873
- 2874
- 2875
- 2876 $m = $this->_os2ip($em);
- 2877 $s = $this->_rsasp1($m);
- 2878 $s = $this->_i2osp($s, $this->k);
- 2879
- 2880
- 2881
- 2882 return $s;
- 2883 }
- 2884
- 2885
- 2886
- 2887
- 2888
- 2889
- 2890
- 2891
- 2892
- 2893
- 2894 function _rsassa_pkcs1_v1_5_verify($m, $s)
- 2895 {
- 2896
- 2897
- 2898 if (strlen($s) != $this->k) {
- 2899 user_error('Invalid signature');
- 2900 return false;
- 2901 }
- 2902
- 2903
- 2904
- 2905 $s = $this->_os2ip($s);
- 2906 $m2 = $this->_rsavp1($s);
- 2907 if ($m2 === false) {
- 2908 user_error('Invalid signature');
- 2909 return false;
- 2910 }
- 2911 $em = $this->_i2osp($m2, $this->k);
- 2912 if ($em === false) {
- 2913 user_error('Invalid signature');
- 2914 return false;
- 2915 }
- 2916
- 2917
- 2918
- 2919 $em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
- 2920 if ($em2 === false) {
- 2921 user_error('RSA modulus too short');
- 2922 return false;
- 2923 }
- 2924
- 2925
- 2926 return $this->_equals($em, $em2);
- 2927 }
- 2928
- 2929
- 2930
- 2931
- 2932
- 2933
- 2934
- 2935
- 2936
- 2937 function setEncryptionMode($mode)
- 2938 {
- 2939 $this->encryptionMode = $mode;
- 2940 }
- 2941
- 2942
- 2943
- 2944
- 2945
- 2946
- 2947
- 2948
- 2949
- 2950 function setSignatureMode($mode)
- 2951 {
- 2952 $this->signatureMode = $mode;
- 2953 }
- 2954
- 2955
- 2956
- 2957
- 2958
- 2959
- 2960
- 2961 function setComment($comment)
- 2962 {
- 2963 $this->comment = $comment;
- 2964 }
- 2965
- 2966
- 2967
- 2968
- 2969
- 2970
- 2971
- 2972 function getComment()
- 2973 {
- 2974 return $this->comment;
- 2975 }
- 2976
- 2977
- 2978
- 2979
- 2980
- 2981
- 2982
- 2983
- 2984
- 2985
- 2986
- 2987
- 2988
- 2989 function encrypt($plaintext)
- 2990 {
- 2991 switch ($this->encryptionMode) {
- 2992 case CRYPT_RSA_ENCRYPTION_NONE:
- 2993 $plaintext = str_split($plaintext, $this->k);
- 2994 $ciphertext = '';
- 2995 foreach ($plaintext as $m) {
- 2996 $ciphertext.= $this->_raw_encrypt($m);
- 2997 }
- 2998 return $ciphertext;
- 2999 case CRYPT_RSA_ENCRYPTION_PKCS1:
- 3000 $length = $this->k - 11;
- 3001 if ($length <= 0) {
- 3002 return false;
- 3003 }
- 3004
- 3005 $plaintext = str_split($plaintext, $length);
- 3006 $ciphertext = '';
- 3007 foreach ($plaintext as $m) {
- 3008 $ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
- 3009 }
- 3010 return $ciphertext;
- 3011
- 3012 default:
- 3013 $length = $this->k - 2 * $this->hLen - 2;
- 3014 if ($length <= 0) {
- 3015 return false;
- 3016 }
- 3017
- 3018 $plaintext = str_split($plaintext, $length);
- 3019 $ciphertext = '';
- 3020 foreach ($plaintext as $m) {
- 3021 $ciphertext.= $this->_rsaes_oaep_encrypt($m);
- 3022 }
- 3023 return $ciphertext;
- 3024 }
- 3025 }
- 3026
- 3027
- 3028
- 3029
- 3030
- 3031
- 3032
- 3033
- 3034
- 3035 function decrypt($ciphertext)
- 3036 {
- 3037 if ($this->k <= 0) {
- 3038 return false;
- 3039 }
- 3040
- 3041 $ciphertext = str_split($ciphertext, $this->k);
- 3042 $ciphertext[count($ciphertext) - 1] = str_pad($ciphertext[count($ciphertext) - 1], $this->k, chr(0), STR_PAD_LEFT);
- 3043
- 3044 $plaintext = '';
- 3045
- 3046 switch ($this->encryptionMode) {
- 3047 case CRYPT_RSA_ENCRYPTION_NONE:
- 3048 $decrypt = '_raw_encrypt';
- 3049 break;
- 3050 case CRYPT_RSA_ENCRYPTION_PKCS1:
- 3051 $decrypt = '_rsaes_pkcs1_v1_5_decrypt';
- 3052 break;
- 3053
- 3054 default:
- 3055 $decrypt = '_rsaes_oaep_decrypt';
- 3056 }
- 3057
- 3058 foreach ($ciphertext as $c) {
- 3059 $temp = $this->$decrypt($c);
- 3060 if ($temp === false) {
- 3061 return false;
- 3062 }
- 3063 $plaintext.= $temp;
- 3064 }
- 3065
- 3066 return $plaintext;
- 3067 }
- 3068
- 3069
- 3070
- 3071
- 3072
- 3073
- 3074
- 3075
- 3076
- 3077 function sign($message)
- 3078 {
- 3079 if (empty($this->modulus) || empty($this->exponent)) {
- 3080 return false;
- 3081 }
- 3082
- 3083 switch ($this->signatureMode) {
- 3084 case CRYPT_RSA_SIGNATURE_PKCS1:
- 3085 return $this->_rsassa_pkcs1_v1_5_sign($message);
- 3086
- 3087 default:
- 3088 return $this->_rsassa_pss_sign($message);
- 3089 }
- 3090 }
- 3091
- 3092
- 3093
- 3094
- 3095
- 3096
- 3097
- 3098
- 3099
- 3100
- 3101 function verify($message, $signature)
- 3102 {
- 3103 if (empty($this->modulus) || empty($this->exponent)) {
- 3104 return false;
- 3105 }
- 3106
- 3107 switch ($this->signatureMode) {
- 3108 case CRYPT_RSA_SIGNATURE_PKCS1:
- 3109 return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
- 3110
- 3111 default:
- 3112 return $this->_rsassa_pss_verify($message, $signature);
- 3113 }
- 3114 }
- 3115
- 3116
- 3117
- 3118
- 3119
- 3120
- 3121
- 3122
- 3123 function _extractBER($str)
- 3124 {
- 3125
- 3126
- 3127
- 3128
- 3129
- 3130
- 3131
- 3132
- 3133
- 3134 $temp = preg_replace('#.*?^-+[^-]+-+[\r\n ]*$#ms', '', $str, 1);
- 3135
- 3136 $temp = preg_replace('#-+[^-]+-+#', '', $temp);
- 3137
- 3138 $temp = str_replace(array("\r", "\n", ' '), '', $temp);
- 3139 $temp = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $temp) ? base64_decode($temp) : false;
- 3140 return $temp != false ? $temp : $str;
- 3141 }
- 3142 }